package com.authine.cloudpivot.ext.applicationservice.organization;

import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.ext.constants.AppConst;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.constants.PlatformConst;
import com.authine.cloudpivot.ext.dto.finance.AccountDto;
import com.authine.cloudpivot.ext.dto.system.OrganizationAttributeDto;
import com.authine.cloudpivot.ext.dto.system.OrganizationDto;
import com.authine.cloudpivot.ext.enums.system.OrganizationAttributeEnum;
import com.authine.cloudpivot.ext.utils.BigDecimalUtils;
import com.authine.cloudpivot.ext.utils.JdbcTemplateUtils;
import com.authine.cloudpivot.ext.utils.finance.AccountUtils;
import com.authine.cloudpivot.ext.utils.system.OrgAttributeUtils;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.authine.hermes.app.launcher.service.ApplicationServiceFoundation.CUSTOM_SERVICE;

/**
 * @ClassName OrganizationInviteCodeService
 * @Description: 供应商邀请码api接口
 * @Author fj
 * @Date 2021/8/25
 * @Version V1.0
 **/
@Path("OrganizationInviteCodeService")
@Slf4j
public class OrganizationInviteCodeService {
    private static final OrganizationApi organizationApi = new OrganizationApi();
    private static final OrganizationAttributeApi attributeApi = new OrganizationAttributeApi();
    private static final NamedParameterJdbcTemplate jdbcTemplate = ApplicationContextUtils.getBean(NamedParameterJdbcTemplate.class);

    /**
     * 客户查询被邀请的供应商组织
     *
     * @param param 请求参数
     * @return 供应商组织id列表
     */
    @Path("listVendorByCustomerId")
    @POST
    @Operation(summary = "客户查询被邀请的供应商组织", tags = CUSTOM_SERVICE)
    public List<String> listVendorByCustomerId(@Parameter OrganizationDto param) {
        List<String> orgIdList = this.getCustomerOrganizationIds(param.getCustomerId(), param.getCustomerId(), Lists.newArrayList());
        List<String> resultIdList = Lists.newArrayList();

        if (!CollectionUtils.isEmpty(orgIdList)) {
            StringBuilder sql = new StringBuilder();
            Map<String, Object> sqlParam = Maps.newHashMap();
            sql.append("select JSON_UNQUOTE(vendor_organization_id -> '$.id') from\n");
            sql.append(JdbcTemplateUtils.getTableName(ModelConst.T_ORGANIZATION_INVITE_CODE, AppConst.PERSONAL_CENTER)).append(" \n");
            sql.append("where CASE WHEN JSON_VALID(customer_organization_id) THEN JSON_UNQUOTE(customer_organization_id -> '$.id') in (:customerId) ELSE NULL END\n");
            sqlParam.put("customerId", orgIdList);
            log.info("sql = {}, parameters = {}", sql, JSONObject.toJSONString(sqlParam));
            List<String> vendorIds = jdbcTemplate.queryForList(sql.toString(), sqlParam, String.class);

            if (!CollectionUtils.isEmpty(vendorIds)) {
                return vendorIds.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
            }
        }
        return resultIdList;
    }

    /**
     * 供应商查询邀请自己的客户列表
     *
     * @param param 请求参数
     * @return 供应商组织id列表
     */
    @Path("listCustomerByVendorId")
    @POST
    @Operation(summary = "供应商查询邀请自己的客户列表", tags = CUSTOM_SERVICE)
    public List<String> listCustomerByVendorId(@Parameter OrganizationDto param) {
        StringBuilder sql = new StringBuilder();
        Map<String, Object> sqlParam = Maps.newHashMap();
        sql.append("select JSON_UNQUOTE(customer_organization_id -> '$.id') from\n");
        sql.append(JdbcTemplateUtils.getTableName(ModelConst.T_ORGANIZATION_INVITE_CODE, AppConst.PERSONAL_CENTER)).append(" \n");
        sql.append("where CASE WHEN JSON_VALID(vendor_organization_id) THEN JSON_UNQUOTE(vendor_organization_id -> '$.id') = :vendorId ELSE NULL END\n");
        sqlParam.put("vendorId", param.getVendorId());
        log.info("sql = {}, parameters = {}", sql, JSONObject.toJSONString(sqlParam));
        List<String> customerIds = jdbcTemplate.queryForList(sql.toString(), sqlParam, String.class);
        log.info("------------------------供应商查询邀请自己的客户列表：{}------------------------", customerIds);
        if (CollectionUtils.isEmpty(customerIds)) {
            return Lists.newArrayList();
        }
        return customerIds;
    }

    /**
     * 递归查询当前组织下邀请关系
     * 一级组织开启邀请码共享，则该组织下面所有的邀请供应商将共享
     * 一级组织未开启邀请码共享，一级组织只会查询自己邀请的供应商，二级组织如果开启，
     * 则二，三级组织共享邀请，以此类推
     *
     * @param id                当前登录人组织id
     * @param currentCustomerId 初始组织id
     * @param ids               返回组织id
     * @return 所有组织id集合
     */
    private List<String> getCustomerOrganizationIds(String id, String currentCustomerId, List<String> ids) {
        OrganizationDto org = organizationApi.getOrgByIdThroughJDBC(OrganizationDto.builder().id(id).build());
        OrganizationAttributeDto organizationAttributeDto = OrganizationAttributeDto.builder()
                .organization_id(org.getId())
                .attribute(OrganizationAttributeEnum.SHARE_INVITE_VENDORS.name())
                .build();
        boolean shareInviteVendors = attributeApi.isEnabledAttribute(organizationAttributeDto);
        // 组织共享
        if (shareInviteVendors) {
            List<OrganizationDto> orgListByOrgId = organizationApi.getOrgListByOrgId(OrganizationDto.builder().id(org.getId()).build());
            orgListByOrgId.forEach(organizationDto -> ids.add(organizationDto.getId()));
        } else {
            ids.add(currentCustomerId);
        }
        // 如果父组织不为null，继续向上查询
        if (!CollectionUtils.isEmpty(org.getParent_id())) {
            return getCustomerOrganizationIds(org.getParent_id().get(0).getId(), currentCustomerId, ids);
        } else {
            return ids;
        }
    }

    /**
     * 根据客户组织ID和供应商组织ID列表 获取该供应商列表中对应客户的平台费率
     *
     * @param param 请求参数
     * @return 结果
     */
    @Path("getVendorPlatformRateByCustomer")
    @POST
    @Operation(summary = "获取该供应商列表中对应客户的平台费率", tags = CUSTOM_SERVICE)
    public Map<String, BigDecimal> getVendorPlatformRateByCustomer(Map<String, Object> param) {
        String customerOrgId = (String) param.get("customerOrgId");
        List<String> vendorOrgIds = (ArrayList) param.get("vendorOrgIds");
        Assert.notNull(customerOrgId, "客户组织ID不能为空");
        Assert.notEmpty(vendorOrgIds, "供应商组织ID不能为空");
        log.info("------------------------获取该供应商列表中对应客户的平台费率请求参数：{}------------------------", JSONObject.toJSONString(param));

        //获取客户根组织，只会存在三级
        OrganizationDto rootOrganization;
        OrganizationDto organization = organizationApi.getOrgByIdThroughJDBC(OrganizationDto.builder().id(customerOrgId).build());
        if (!CollectionUtils.isEmpty(organization.getParent_id()) && StringUtils.isNotBlank(organization.getParent_id().get(0).getId())) {
            OrganizationDto pOrganization = organizationApi.getOrgByIdThroughJDBC(OrganizationDto.builder().id(organization.getParent_id().get(0).getId()).build());
            if (!CollectionUtils.isEmpty(pOrganization.getParent_id())) {
                rootOrganization = organizationApi.getOrgByIdThroughJDBC(OrganizationDto.builder().id(pOrganization.getParent_id().get(0).getId()).build());
            } else {
                rootOrganization = pOrganization;
            }
        } else {
            rootOrganization = organization;
        }

        String parentIdByOrgId = rootOrganization.getId();
        //共享邀请供应商属性是否开启
        boolean shareInviteVendors = OrgAttributeUtils.isEnabledAttribute(parentIdByOrgId, OrganizationAttributeEnum.SHARE_INVITE_VENDORS);

        List<String> selfSubCustomerOrgIds = Collections.singletonList(customerOrgId);
        //是否开启共享邀请供应商
        if (shareInviteVendors) {
            selfSubCustomerOrgIds = organizationApi.getOrgListByOrgId(OrganizationDto.builder().id(parentIdByOrgId).build())
                    .stream().map(OrganizationDto::getId).collect(Collectors.toList());
        }

        //客户组织与供应商是否存在邀请关系
        List<String> inviteVendorIds = JdbcTemplateUtils.builder(AppConst.PERSONAL_CENTER, ModelConst.T_ORGANIZATION_INVITE_CODE)
                .selectField("vendor_organization_id -> '$.id'")
                .in("JSON_UNQUOTE(customer_organization_id -> '$.id')", selfSubCustomerOrgIds)
                .in("JSON_UNQUOTE(vendor_organization_id -> '$.id')", vendorOrgIds)
                .queryForList(String.class);
        Map<String, BigDecimal> results = new HashMap<>();
        //没有邀请关系的平台税率等于客户结算组织的平台费率
        if (inviteVendorIds == null || inviteVendorIds.isEmpty()) {
            results = getNonInvitePlatform(vendorOrgIds, organization);
        } else {
            //存在邀请关系的供应商
            Set<String> exist = vendorOrgIds.stream().filter(inviteVendorIds::contains).collect(Collectors.toSet());
            //不存在邀请关系的供应商
            Set<String> nonExist = vendorOrgIds.stream().filter(t -> !inviteVendorIds.contains(t)).collect(Collectors.toSet());
            if (!exist.isEmpty()) {
                //邀请关系
                AccountDto accountDto = AccountUtils.getAccountById(organization.getAccount_id());
                BigDecimal invitePlatform = accountDto.getPlatform_rate().compareTo(PlatformConst.PLATRATE) == 1 ? BigDecimalUtils.sub(accountDto.getPlatform_rate(), PlatformConst.PLATRATE) : BigDecimal.ZERO;
                for (String vendorOrgId : exist) {
                    results.put(vendorOrgId, invitePlatform);
                }
            }
            if (!nonExist.isEmpty()) {
                //不存在邀请关系
                results.putAll(getNonInvitePlatform(nonExist, organization));
            }
        }
        log.info("------------------------获取该供应商列表中对应客户的平台费率返回结果：{}------------------------", JSONObject.toJSONString(results));
        return results;
    }

    @NotNull
    private Map<String, BigDecimal> getNonInvitePlatform(Collection<String> vendorOrgIds, OrganizationDto organization) {
        AccountDto accountDto = AccountUtils.getAccountById(organization.getAccount_id());
        BigDecimal nonInvitePlatform = accountDto.getPlatform_rate().compareTo(BigDecimal.ZERO) == 0 ? PlatformConst.PLATRATE : accountDto.getPlatform_rate();
        Map<String, BigDecimal> result = new HashMap<>();
        for (String vendorOrgId : vendorOrgIds) {
            result.put(vendorOrgId, nonInvitePlatform);
        }
        return result;
    }
}
